package megrez.bussiness.system.service;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;
import megrez.bussiness.system.entity.Area;
import megrez.bussiness.system.repository.AreaRepository;
import megrez.bussiness.system.util.SystemErrorCode;
import megrez.bussiness.system.util.SystemException;
import megrez.common.util.EntityMissingException;

/**
 * 地区服务
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@Service
@RequiredArgsConstructor
public class AreaService {
    private final AreaRepository areaRepository;

    @Transactional(rollbackFor = Exception.class)
    public Area save(Long parentId, Area data) {
        Optional.ofNullable(parentId).map(id -> this.findById(parentId)).ifPresent(p -> {
            data.setParent(p);
            if (Boolean.TRUE.equals(p.getIsLeaf())) {
                p.setIsLeaf(false);
                areaRepository.save(p);
            }
        });
        return areaRepository.save(data);
    }

    @Transactional(rollbackFor = Exception.class)
    public Area update(Long id, Area area) {
        Area entity = this.findById(id);
        entity.copy(area);
        return areaRepository.save(entity);

    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(Long areaId) {
        areaRepository.findById(areaId).ifPresent(area -> {
            if (area.getChildren().size()> 0) {
                throw new SystemException(SystemErrorCode.DELETE_AREA_HAS_CHILD);
            }

            areaRepository.delete(area);
        });

    }

    public Area findById(Long id) {
        return areaRepository.findById(id).orElseThrow(EntityMissingException::new);
    }

    /**
     * 获取所有地区全称， key=code, value=全称
     * 
     * @return
     */
    public Map<String, String> getCodeNameMap() {
        List<Area> allAreaList = areaRepository.findAll();
        // key=code, value=名称
        Map<String, String> allAreaMap = allAreaList.stream().collect(Collectors.toMap(Area::getCode, Area::getName));

        // key=id, value=全称
        Map<String, String> rslt = new TreeMap<>();
        allAreaList.stream()
                // 排序
                .sorted(Comparator.comparing(Area::getPathCode))
                .forEachOrdered(a -> {
                    String value = Stream.of(a.getPathCode().split(Area.PATH_SEP))
                            .map(allAreaMap::get)
                            .collect(Collectors.joining(Area.PATH_SEP));
                    rslt.put(a.getCode(), value);
                });

        return rslt;
    }

    public Area findByCode(String code) {
        return areaRepository.findByCode(code).orElseThrow(EntityMissingException::new);
    }

    /**
     * 查询所有下级
     * 
     * @param id 主键
     * @return
     */
    public List<Area> getGrandchildren(Long id) {
        Area parent = this.findById(id);
        List<Area> entities = areaRepository.findByPathCodeLike(parent.getPathCode() + Area.PATH_SEP + "%");
        Collections.sort(entities, Comparator.comparing(Area::getPathCode));
        return entities;
    }
}
